package com.example.limit.rule;

import com.example.limit.entity.PurchaseRule;
import com.example.limit.mapper.PurchaseRuleMapper;
import org.jeasy.rules.api.*;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 基于Easy Rules的购买规则引擎
 */
@Service
public class PurchaseRuleEngine {
    
    private final PurchaseRuleMapper ruleMapper;
    private final RulesEngine rulesEngine;
    
    public PurchaseRuleEngine(PurchaseRuleMapper ruleMapper) {
        this.ruleMapper = ruleMapper;
        
        // 配置规则引擎参数
        RulesEngineParameters parameters = new RulesEngineParameters()
            .skipOnFirstAppliedRule(false)  // 不跳过，执行所有规则
            .skipOnFirstFailedRule(false)   // 不跳过失败规则
            .skipOnFirstNonTriggeredRule(false) // 不跳过未触发规则
            .priorityThreshold(10);         // 优先级阈值
        
        this.rulesEngine = new DefaultRulesEngine(parameters);
    }
    
    /**
     * 使用规则引擎校验购买限制
     */
    public RuleEngineResult checkPurchaseLimit(Long userId, String productId, 
                                              String categoryId, int quantity,
                                              Map<String, Object> context) {
        
        // 准备事实数据
        Facts facts = prepareFacts(userId, productId, categoryId, quantity, context);
        
        // 获取并注册规则
        Rules rules = loadRules();
        
        // 执行规则引擎
        rulesEngine.fire(rules, facts);
        
        // 收集执行结果
        return collectResults(facts, rules);
    }
    
    /**
     * 准备事实数据
     */
    private Facts prepareFacts(Long userId, String productId, String categoryId, 
                              int quantity, Map<String, Object> context) {
        Facts facts = new Facts();
        
        Map<String, Object> purchaseContext = new HashMap<>();
        purchaseContext.put("userId", userId);
        purchaseContext.put("productId", productId);
        purchaseContext.put("categoryId", categoryId);
        purchaseContext.put("quantity", quantity);
        purchaseContext.put("purchaseTime", LocalDateTime.now());
        
        // 添加上下文参数
        if (context != null) {
            purchaseContext.putAll(context);
        }
        
        facts.put("context", purchaseContext);
        facts.put("results", new HashMap<String, Object>());
        
        return facts;
    }
    
    /**
     * 加载数据库规则并转换为Easy Rules规则
     */
    private Rules loadRules() {
        List<PurchaseRule> dbRules = ruleMapper.selectActiveRules();
        
        Rules rules = new Rules();
        
        for (PurchaseRule dbRule : dbRules) {
            PurchaseRuleDefinition ruleDefinition = new PurchaseRuleDefinition(dbRule);
            Rule easyRule = ruleDefinition.toEasyRule();
            
            // 设置规则优先级（数据库规则的优先级）
            if (dbRule.getPriority() != null) {
                // Easy Rules优先级是数字越小优先级越高，与我们的定义相反
                int easyRulesPriority = 100 - dbRule.getPriority(); // 转换优先级
                ((org.jeasy.rules.support.RuleDefinition) easyRule).setPriority(easyRulesPriority);
            }
            
            rules.register(easyRule);
        }
        
        return rules;
    }
    
    /**
     * 收集规则执行结果
     */
    private RuleEngineResult collectResults(Facts facts, Rules rules) {
        Map<String, Object> results = facts.get("results");
        List<RuleExecutionDetail> details = new ArrayList<>();
        
        boolean overallResult = true;
        String message = "所有规则校验通过";
        
        // 分析每个规则的执行结果
        for (Rule rule : rules) {
            boolean ruleTriggered = results.containsKey("rule_" + extractRuleId(rule.getName()));
            boolean rulePassed = ruleTriggered;
            
            RuleExecutionDetail detail = new RuleExecutionDetail(
                extractRuleId(rule.getName()),
                rule.getName(),
                rule.getDescription(),
                ruleTriggered,
                rulePassed
            );
            
            details.add(detail);
            
            if (!rulePassed) {
                overallResult = false;
                message = "部分规则校验失败";
            }
        }
        
        // 按优先级排序详情
        details.sort(Comparator.comparing(RuleExecutionDetail::getRuleId));
        
        return new RuleEngineResult(overallResult, message, details);
    }
    
    private Long extractRuleId(String ruleName) {
        // Rule_123 -> 123
        return Long.parseLong(ruleName.substring(5));
    }
    
    /**
     * 规则引擎结果
     */
    public static class RuleEngineResult {
        private final boolean passed;
        private final String message;
        private final List<RuleExecutionDetail> ruleDetails;
        
        public RuleEngineResult(boolean passed, String message, List<RuleExecutionDetail> ruleDetails) {
            this.passed = passed;
            this.message = message;
            this.ruleDetails = ruleDetails;
        }
        
        public boolean isPassed() { return passed; }
        public String getMessage() { return message; }
        public List<RuleExecutionDetail> getRuleDetails() { return ruleDetails; }
    }
    
    /**
     * 规则执行详情
     */
    public static class RuleExecutionDetail {
        private final Long ruleId;
        private final String ruleName;
        private final String description;
        private final boolean triggered;
        private final boolean passed;
        
        public RuleExecutionDetail(Long ruleId, String ruleName, String description, 
                                 boolean triggered, boolean passed) {
            this.ruleId = ruleId;
            this.ruleName = ruleName;
            this.description = description;
            this.triggered = triggered;
            this.passed = passed;
        }
        
        public Long getRuleId() { return ruleId; }
        public String getRuleName() { return ruleName; }
        public String getDescription() { return description; }
        public boolean isTriggered() { return triggered; }
        public boolean isPassed() { return passed; }
    }
}